/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.buffer;

import com.aduib.boot.common.exception.IoException;

import java.io.InputStream;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;

/**
 * @description: BufferedSource
 * @author: zzh
 * @date: 2021/11/22 10:41
 */
public interface BufferedSource extends Source, ReadableByteChannel {

  Buffer getBuffer();

  /**
   * Returns true if there are no more bytes in this source. This will block until there are bytes
   * to read or the source is definitely exhausted.
   */
  boolean exhausted() throws IoException;

  /**
   * Returns true when the buffer contains at least {@code byteCount} bytes, expanding it as
   * necessary. Returns false if the source is exhausted before the requested bytes can be read.
   */
  boolean request(long byteCount) throws IoException;

  /** Removes a byte from this source and returns it. */
  byte readByte() throws IoException;

  /** Removes two bytes from this source and returns a big-endian short. */
  short readShort() throws IoException;

  /** Removes four bytes from this source and returns a big-endian int. */
  int readInt() throws IoException;

  /** Removes eight bytes from this source and returns a big-endian long. */
  long readLong() throws IoException;

  float readFloat() throws IoException;

  double readDouble() throws IoException;

  /**
   * Reads and discards {@code byteCount} bytes from this source. Throws an {@link
   * java.io.EOFException} if the source is exhausted before the requested bytes can be skipped.
   */
  void skip(long byteCount) throws IoException;

  /** Removes all bytes from this and returns them as a byte array. */
  byte[] readByteArray() throws IoException;

  /**
   * Removes {@code byteCount} bytes from this and returns them as a byte array.
   *
   * @param byteCount
   */
  byte[] readByteArray(int byteCount) throws IoException;

  /**
   * Removes up to {@code sink.length} bytes from this and copies them into {@code sink}. Returns
   * the number of bytes read, or -1 if this source is exhausted.
   */
  int read(byte[] sink) throws IoException;

  /**
   * Removes exactly {@code sink.length} bytes from this and copies them into {@code sink}. Throws
   * an {@link java.io.EOFException} if the requested number of bytes cannot be read.
   */
  void readFully(byte[] sink) throws IoException;

  /**
   * Removes up to {@code byteCount} bytes from this and copies them into {@code sink} at {@code
   * offset}. Returns the number of bytes read, or -1 if this source is exhausted.
   */
  int read(byte[] sink, int offset, int byteCount) throws IoException;

  /**
   * Removes exactly {@code byteCount} bytes from this and appends them to {@code sink}. Throws an
   * {@link java.io.EOFException} if the requested number of bytes cannot be read.
   */
  void readFully(Buffer sink, int byteCount) throws IoException;

  /**
   * Removes all bytes from this and appends them to {@code sink}. Returns the total number of bytes
   * written to {@code sink} which will be 0 if this is exhausted.
   */
  long readAll(Sink sink) throws IoException;

  /** Removes {@code byteCount} bytes from this, decodes them as UTF-8, and returns the string. */
  String readStringUtf8(int byteCount) throws IoException;
  /**
   * Removes {@code byteCount} bytes from this, decodes them as {@code charset}, and returns the
   * string.
   */
  String readString(int byteCount, Charset charset) throws IoException;

  /** Returns an input stream that reads from this source. */
  InputStream inputStream();
}
